package com.qf.component;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * @Author Ayases
 * @Date 2025/4/2 19:45
 * @Desc
 */

@Component  // 让Spring容器管理这个Bean
@Aspect  // 让框架知道,这是一个切面
public class MyAspect {
    /**
     * 将目标方法路径,提取成公共的路径,直接调用
     * 后续其他增强就不用每次都写
     */
    @Pointcut("execution(* com.qf.service.*.*(..))")
    public void myPointcut() {}



    /**
     * 自己定义一个方法,用于增强
     * 例如: 权限校验
     * @Before注解,可以在目标方法执行前,执行这个myBefore方法
     * 注解内写的就是,目标方法路径
     *  第一个* ,是返回值任意
     *  com.qf.service.impl.* 是指impl包下的任意类
     *  .* 类中任意方法名
     *  (..) 方法参数任意
     * ------------------------
     * 参数 JoinPoint,就是目标对象
     */


    @Before("execution(* com.qf.service.impl.*.*(..))")
    public void myBefore(JoinPoint joinPoint) {
        System.out.println("方法执行前: 权限校验" );
        System.out.println("目标方法名:"+ joinPoint.getSignature( ).getName( ));

        // 权限校验,如果通过,无事发生,正常执行
        // 权限校验,如果不通过,可以抛出异常,让代码停止,目标方法不执行
        // throw new RuntimeException("权限校验失败");
    }


    @Around("myPointcut()")
    public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable {
        // 目标方法前:
        System.out.println("开启事务/权限校验" );

        // 目标方法执行
        Object ret = joinPoint.proceed( );
        System.out.println("目标方法返回值---> " + ret );
        // 目标方法后:
        System.out.println("提交事务/日志记录" );
        return ret;
    }


    /**
     JoinPoint 是目标方法对象
     */
    @Before("myPointcut()")
    public void myBefore002(JoinPoint joinPoint) {
        // 目标对象
        Object target = joinPoint.getTarget( );
        System.out.println("target = " + target);
        // 获得目标方法签名(方法名)
        Signature signature = joinPoint.getSignature( );
        System.out.println("signature = " + signature);

        System.out.println("前置通知--->权限校验--->OK" );

        // 假设权限校验没有通过,通过抛出异常让代码停下,不再执行目标方法
        // System.out.println("前置通知--->权限校验--->ERROR" );
        // throw new RuntimeException("权限校验--->ERROR");
    }



    @After("myPointcut()")
    public void myAfter() {
        // 获得ip
        // 获得时间
        // 获得人名
        // 获得日志描述信息
        System.out.println("后置通知--->记录日志,释放资源" );
    }



    /**
     * 后置返回增强,一般用于接收目标方法的返回值
     * --------------------------------
     * 当注解括号内参数只有一个,且参数名是value,那么可以省略value直接写值
     * 当多于1个参数,所有参数都需要写k=v
     * ---------------------------------
     * @AfterReturning 后置返回增强,用于目标方法的返回值
     *  参数value用于指定目标方法
     *  参数returning用于指定返回值,该返回值需要定义在本方法的参数上
     */
    @AfterReturning(value = "myPointcut()",returning = "ret")
    public Object myAfterRet(Object ret) {
        System.out.println("后置返回通知,接收到目标方法返回值--->" + ret);
        return ret;
    }

    @AfterThrowing(value = "myPointcut()",throwing = "e")
    public void myException(Exception e) {
        System.out.println("目标方法报的错---> " + e.getMessage());
    }








}
